﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace XWord.Fundamental.Domain
{
    [Serializable]
    public abstract class AbstractEntity<TIdentity> : IGenericEntity<TIdentity>, IEquatable<IGenericEntity<TIdentity>>
    {
        // Fields
        private int? requestedHashCode;

        // Methods
        protected AbstractEntity()
        {
        }

        public virtual bool CustomEquals(object other)
        {
            return false;
        }

        public virtual bool Equals(IGenericEntity<TIdentity> other)
        {
            if (null == other)
            {
                return false;
            }
            if (object.ReferenceEquals(this, other))
            {
                return true;
            }
            bool otherIsTransient = object.Equals(other.Id, default(TIdentity));
            bool thisIsTransient = this.IsTransient();
            if (otherIsTransient && thisIsTransient)
            {
                return object.ReferenceEquals(other, this);
            }
            return other.Id.Equals(this.Id);
        }

        public override bool Equals(object obj)
        {
            IGenericEntity<TIdentity> that = obj as IGenericEntity<TIdentity>;
            return this.Equals(that);
        }

        public override int GetHashCode()
        {
            if (!this.requestedHashCode.HasValue)
            {
                this.requestedHashCode = new int?(this.IsTransient() ? base.GetHashCode() : this.Id.GetHashCode());
            }
            return this.requestedHashCode.Value;
        }

        protected bool IsTransient()
        {
            return object.Equals(this.Id, default(TIdentity));
        }

        // Properties
        public abstract TIdentity Id { get; set; }
    }


}
